package kevin.framework.basic.common.user;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;

import kevin.framework.basic.common.thread.RequestThreadHolder;
import kevin.framework.basic.common.thread.ResponseThreadHolder;
import kevin.framework.basic.common.utils.SpringContextUtil;
import kevin.framework.basic.common.utils.SysConfigParams;
import kevin.framework.basic.domain.Func;
import kevin.framework.basic.domain.Menu;
import kevin.framework.basic.domain.User;
import kevin.framework.basic.domain.UserRole;
import kevin.framework.basic.service.IFuncService;
import kevin.framework.basic.service.IMenuService;
import kevin.framework.basic.service.IUserRoleService;

/**
 * @ClassName: LoginUserContext
 * @Description: TODO
 * @author kevin.huang
 * @date 2016年4月23日 下午1:45:11
 */
public abstract class LoginUserContext implements ILoginUserContext {

	private IMenuService menuService = null;
	private IFuncService funcService = null;
	private IUserRoleService UserRoleService = null;

	protected IUserRoleService getUserRoleService() {
		if (UserRoleService == null) {
			UserRoleService = (IUserRoleService) SpringContextUtil.getBean("userRoleService");
		}
		return UserRoleService;
	}

	protected IFuncService getFuncService() {
		if (funcService == null) {
			funcService = (IFuncService) SpringContextUtil.getBean("funcService");
		}
		return funcService;
	}

	protected IMenuService getMenuService() {
		if (menuService == null) {
			menuService = (IMenuService) SpringContextUtil.getBean("menuService");
		}
		return menuService;
	}

	/**
	 * @Fields expiry : 登录过期时间，默认20分钟
	 */
	protected int expiry = 20;

	/**
	 * @Fields updateRate : 平滑更新session(memcached)的频率 updateRate=3 表示当时间过了 expiry/3
	 *         间隔后才重复更新
	 */
	protected int updateRate = 3;

	/**
	 * @Title: getSysCookie @Description: 获取系统cookies @param request @return @throws
	 */
	@Override
	public Cookie getCookie(String key) {
		HttpServletRequest request = this.getRequest();
		Cookie[] cookies = request.getCookies();
		Cookie cookie = null;
		if (cookies != null) {
			for (Cookie c : cookies) {
				if (c.getName().equals(key)) {
					cookie = c;
					break;
				}
			}
		}
		return cookie;
	}

	/**
	 * @Title: getIpAddr @Description: 获取用户登录的ip @param request @return @throws
	 */
	@Override
	public String getIpAddr() {
		HttpServletRequest request = this.getRequest();
		String ipAddress = null;
		// ipAddress = this.getRequest().getRemoteAddr();
		ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
			if ("127.0.0.1".equals(ipAddress)) {
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
					ipAddress = inet.getHostAddress();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
			}
		}
		// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
															// = 15
			if (ipAddress.indexOf(",") > 0) {
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
			}
		}
		return ipAddress;
	}
	@Override
	public HttpServletRequest getRequest() {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		if (ra == null) {
			return RequestThreadHolder.getRequest();
		}
		HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
		return request;
	}

	protected HttpSession getSession() {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		HttpServletRequest request;
		if (ra == null) {
			request = RequestThreadHolder.getRequest();
		} else {
			request = ((ServletRequestAttributes) ra).getRequest();
		}
		HttpSession session = null;
		try {
			session = request.getSession();
		} catch (Exception ex) {
		}
		return session;
	}

	protected String getSessionId() throws Exception {
		return getSession().getId();
	}

	protected String getLoginKeyFromRequest() throws Exception {
		Cookie cookie = getCookie(SysConfigParams.cookieKey);
		if (cookie == null) {
			return null;
		}
		String value = cookie.getValue();
		return value;
	}

	@Override
	public String writeLoginCookies(LoginUser loginUser) throws Exception {
		updateUserLoginTime(loginUser);
		responseCookie(SysConfigParams.cookieKey, loginUser.userKey, true);
		return "";
	}

	protected void updateUserLoginTime(LoginUser loginUser) {
		User updateUser = new User();
		updateUser.setId(loginUser.getId());
		updateUser.setLoginIp(loginUser.getLoginIp());
	}

	protected void responseCookie(String cookieKey, String cookieValue, boolean httpOnly) {
		try {
			Cookie loginCookie = new Cookie(cookieKey, cookieValue);
			loginCookie.setMaxAge(-1);
			String ctxString = SysConfigParams.webHttpContext;
			loginCookie.setPath(ctxString);
			loginCookie.setHttpOnly(httpOnly);
			HttpServletResponse response = ResponseThreadHolder.getResponse();
			response.addCookie(loginCookie);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@Override
	public Map<String, List<UserFunc>> getLoginUserAuthMap(LoginUser user) throws Exception {
		return user.getAuthMap();
	}

	@Override
	public List<Menu> getUserMenus(LoginUser user) throws Exception {
		return (List<Menu>) user.getUserData("userMenus");
	}

	/**
	 * 加载用户权限数据 放到 LoginUser返回
	 **/
	@Override
	public LoginUser loadUserAuthData(User user) throws Exception {
		LoginUser loginUser = new LoginUser(user);
		String ip = getIpAddr();
		loginUser.setLoginIp(ip);
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("isEnable", 1);
		param.put("isVisible", 1);
		Map<String, Menu> menuMap = getMenuService().selectMap(param);
		List<Menu> userMenus = loadUserMenus(menuMap, loginUser);
		loginUser.setUserData("userMenus", userMenus);
		loginUser.setLang(SysConfigParams.lang);
		return loginUser;
	}

	/**
	 * 加载用户菜单，并关联读取用户权限功能loginUser.setAuthMap(authMap)
	 **/
	protected List<Menu> loadUserMenus(Map<String, Menu> menuMap, LoginUser loginUser) throws Exception {
		Set<Entry<String, Menu>> menuSet = menuMap.entrySet();
		List<Menu> userMenus = new ArrayList<Menu>();
		// 非超级加载权限资源
		if (!loginUser.isSuperAdmin()) {
			Map<String, List<UserFunc>> authMap = loadUserFunc(menuMap, loginUser, userMenus);
			loginUser.setAuthMap(authMap);
		} else {
			for (Entry<String, Menu> en : menuSet) {
				userMenus.add(en.getValue());
			}
		}
		Collections.sort(userMenus, new Comparator<Menu>() {
			@Override
			public int compare(Menu arg0, Menu arg1) {
				return arg0.getOrderIndex().compareTo(arg1.getOrderIndex());
			}
		});
		return userMenus;
	}

	/***
	 * 加载用户可访问的url 按钮资源数据 不需要提取菜单到 userMenus 时候 userMenus 可空
	 **/
	protected Map<String, List<UserFunc>> loadUserFunc(Map<String, Menu> menuMap, LoginUser loginUser,
			List<Menu> userMenus) throws Exception {
		Set<Entry<String, Menu>> menuSet = menuMap.entrySet();
		Map<String, List<UserFunc>> authMap = new HashMap<String, List<UserFunc>>();
		List<Func> funcList = getFuncService().login(loginUser.getId());
		Set<String> tmp = new HashSet<String>();
		for (Func func : funcList) {
			String mId = func.getMenuId();
			Menu m = menuMap.get(mId);
			if (userMenus != null) {
				if (!tmp.contains(mId)) {
					userMenus.add(m);
					tmp.add(mId);
					getParentMenu(menuMap, m.getPid(), userMenus, tmp);
				}
			}
			String controller = "/" + m.getController();
			List<UserFunc> fList;
			if (authMap.containsKey(controller)) {
				fList = authMap.get(controller);
			} else {
				fList = new ArrayList<UserFunc>();
			}
			fList.add(new UserFunc("1".equals(func.getIsLog() ), func.getFuncCode()));
			authMap.put(controller, fList);
		}
		if (userMenus != null) {
			Set<String> controllerSet = SysConfigParams.getNoValidController();
			for (Entry<String, Menu> en : menuSet) {
				Menu menu = en.getValue();
				String ctr = menu.getController();
				if (StringUtils.isNotEmpty(ctr) && controllerSet.contains(ctr)) {
					userMenus.add(menu);
					getParentMenu(menuMap, menu.getPid(), userMenus, tmp);
				}
			}
		}
		return authMap;
	}

	/**
	 * 加载用户角色 loginUser.getUserData("roles")获取
	 **/
	protected List<UserRole> loadUserRole(LoginUser loginUser) throws Exception {
		Map<String, Object> param2 = new HashMap<String, Object>();
		param2.put("userId", loginUser.getId());
		param2.put("roleStatus", 1);
		List<UserRole> listUr = getUserRoleService().selectParam(param2);
		loginUser.setUserData("roles", listUr);
		return listUr;
	}

	private void getParentMenu(Map<String, Menu> menuMap, String pid, List<Menu> userMenu, Set<String> hasSet) {
		Menu m = menuMap.get(pid);
		if (m != null) {
			if (!hasSet.contains(m.getId())) {
				hasSet.add(m.getId());
				userMenu.add(m);
				String _pid = m.getPid();
				if (!"0".equals(_pid)) {
					getParentMenu(menuMap, _pid, userMenu, hasSet);
				}
			}
		}
	}
}
